#!/usr/bin/env bash

# 用于生成Python工程的脚手架及范例文件，该脚手架充分参考行业内最通用的工程结构，脚本和文件注释全部用中文。
# 1. 工程依赖管理采用pip，首先检查系统是否已安装pip。
# 2. 单元测试采用pytest框架，同样需确认是否已安装pytest。
# 3. 脚本启动后会以交互方式询问工程名称，所选名称将作为工程目录名。
# 4. 对用户输入进行校验：若用户仅按回车，则采用默认工程名“my_py_project”；否则，将持续循环直至用户输入符合规范的工程名。
# 5. 命名规则如下：
#    ① 必须以字母起始；
#    ② 只能包含字母、数字与下划线；
#    ③ 长度限制在3至63个字符范围内；
#    ④ 不允许以数字开头；
#    ⑤ 不得出现连续的下划线；
#    ⑥ 结尾必须为字母或数字。
# 6. 所有文件统一使用UTF-8编码，注释使用中文。Python脚本的Shebang中指定使用/usr/bin/python，用Tab键缩进。
# 7. 创建.vscode/settings.json文件，用以配置VS Code的调试环境，其中初始化file.encoding为UTF-8。
# 8. 创建Makefile，用于执行安装、初始化、测试和清理操作。
# 9. 创建setup.py和requirements.txt文件，用于安装依赖包。
# 10. 创建.gitignore文件，用于忽略VS Code生成的临时文件。


# 检查pip是否已安装
function check_pip {
	if ! command -v pip &>/dev/null; then
	echo "未检测到pip。请在继续之前先安装pip。"
	exit 1
	fi
}

# 检查pytest是否已安装，如未安装则自动安装
function check_pytest {
	if ! command -v pytest &>/dev/null; then
	echo "未检测到pytest。正在安装pytest..."
	pip install pytest
	fi
}

# 询问并获取有效的项目名称
function get_valid_project_name {
	local proj_name="my_py_project"
	while true; do
	read -rp "请输入项目名称（默认：$proj_name）：" user_input
	if [ -z "$user_input" ]; then
		proj_name=$user_input
		break
	elif [[ "$user_input" =~ ^[a-zA-Z][a-zA-Z0-9_]{1,61}[a-zA-Z0-9]$ ]] && ! [[ "$user_input" =~ _{2,} ]]; then
		proj_name=$user_input
		break
	else
		echo "无效的项目名称。请遵循以下命名规则："
		echo "① 以字母起始"
		echo "② 只能包含字母、数字与下划线"
		echo "③ 长度限制在3至63个字符范围内"
		echo "④ 不允许以数字开头"
		echo "⑤ 不得出现连续的下划线"
		echo "⑥ 结尾必须为字母或数字"
	fi
	done
	echo $proj_name
}

# 创建项目目录结构及范例文件
function create_project_structure {
	local proj_name=$1

	mkdir -p "$proj_name"/.vscode
	mkdir -p "$proj_name/src/$proj_name"
	mkdir -p "$proj_name/tests"

	# 创建空的__init__.py文件
	touch "$proj_name/src/$proj_name/__init__.py"
	touch "$proj_name/tests/__init__.py"

	# 创建main.py和test_main.py范例文件
	cat << EOF > "$proj_name/src/$proj_name/main.py"
#!/usr/bin/env python
# -*- coding: utf-8 -*-

def main():
	"""
	程序主入口函数
	"""
	print("你好，世界！")

if __name__ == "__main__":
	main()
EOF

cat << EOF > "$proj_name/tests/test_main.py"
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pytest
from src.$proj_name import main

def test_main():
	"""
	测试main函数
	"""
	assert main() == None

if __name__ == "__main__":
	pytest.main()
EOF

# 设置所有Python文件的UTF-8编码和Shebang
find "$proj_name" -name "*.py" -exec sed -i '1s|^|#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n|' {} \;

# 创建VS Code调试环境配置文件
cat << EOF > "$proj_name/.vscode/settings.json"
{
	"files.encoding": "utf8"
}
EOF

# 创建Makefile
cat << EOF > "$proj_name/Makefile"
# 项目名称：YourProjectName
# 版权所有 (c) 2024 YourCompany 或 AuthorName。保留所有权利。
#
# 本Makefile用于管理YourProjectName项目的各种构建与开发任务，
# 包括依赖安装、运行主程序、执行测试以及清理开发过程中生成的文件。
#
# 使用方法：
#   make install      - 从requirements.txt安装项目依赖
EOF

echo "#   make run          - 执行位于src/$proj_name/main.py的主Python脚本">>"$proj_name/Makefile"

cat << EOF >> "$proj_name/Makefile"
#   make test         - 使用pytest运行tests/目录下的所有测试
#   make clean        - 移除开发过程中产生的中间文件和缓存

.PHONY: install test clean run

install:
	# 安装项目依赖
	pip install -r requirements.txt
run:
EOF

echo "	python src/$proj_name/main.py">>"$proj_name/Makefile"


cat << EOF >> "$proj_name/Makefile"

test:
	pytest tests/

clean:
	# 清理生成的.pyc文件、__pycache__目录及pytest缓存
	find . -type f -name "*.pyc" -delete
	find . -type d -name "__pycache__" -exec rm -rf {} +
	rm -rf .pytest_cache
EOF

# 创建setup.py文件
cat << EOF > "$proj_name/setup.py"
from setuptools import setup

setup(
	name="$proj_name",
	version="0.1.0",
	packages=["src.$proj_name"],
	install_requires=[],
	entry_points={
		"console_scripts": [
			"$proj_name = src.$proj_name.main:main"
		]
	},
)
EOF

# 创建requirements.txt文件
touch "$proj_name/requirements.txt"

# 创建.gitignore文件
cat << EOF > "$proj_name/.gitignore"
.vscode/*
*.pyc
__pycache__/
.DS_Store
EOF
}

# 主程序执行
check_pip
check_pytest
proj_name=$(get_valid_project_name)
create_project_structure "$proj_name"
echo "项目 '$proj_name' 成功创建。"